import 'dart:async';
import 'dart:convert';
import 'dart:math';

import 'package:crypto/crypto.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:get/get.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:mziot/app/config/constant.dart';
import 'package:mziot/app/data/user_entity.dart';
import 'package:mziot/app/modules/auth/mine_provider.dart';
import 'package:mziot/app/routes/app_pages.dart';
import 'package:mziot/app/tools/global_const.dart';
import 'package:mziot/app/tools/public_provider.dart';
import 'package:mziot/app/tools/tools.dart';
import 'package:mziot/generated/locales.g.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';

enum LoginType { code, password }

enum ThirdType { facebook, apple, google, ins }

class AuthLoginController extends GetxController {
  MineProvider provider = MineProvider();
  //controller
  TextEditingController emailController = TextEditingController();
  TextEditingController codeController = TextEditingController();
  //state
  Rx<LoginType> loginType = LoginType.code.obs;
  RxBool codeEnable = false.obs;
  RxBool loginEnable = false.obs;
  //data
  RxString email = ''.obs;
  RxString code = ''.obs;
  RxString password = ''.obs;
  RxInt time = 61.obs;
  Timer? _timer;
  //类型 1 ：fb 2：ins 3：google 4： apple
  int thirdType = 1;
  final isSee = true.obs;
  final isCheck = false.obs;
  int isNext = 0;

  @override
  void onInit() {
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();

    email.subject.listen((element) => vaildInfo());
    code.subject.listen((element) => vaildInfo());
    password.subject.listen((element) => vaildInfo());
  }

  void vaildInfo() {
    if (!email.value.isEmail) {
      codeEnable.value = false;
      loginEnable.value = false;
      return;
    }
    codeEnable.value = true;

    if (code.value.length != 4 && loginType.value == LoginType.code) {
      loginEnable.value = false;
      return;
    }

    if (password.value.length < 8 && loginType.value == LoginType.password) {
      loginEnable.value = false;
      return;
    }

    loginEnable.value = true;
  }

  void signInWithFacebook() async {
    thirdType = 1;
    final LoginResult loginResult = await FacebookAuth.instance.login();
    if (loginResult.accessToken == null) {
      showToast(LocaleKeys.tips_login_failed.tr);
      EasyLoading.dismiss();
      return;
    }
    EasyLoading.show();
    final OAuthCredential facebookAuthCredential =
        FacebookAuthProvider.credential(loginResult.accessToken!.token);
    if (facebookAuthCredential.accessToken == null) {
      showToast(LocaleKeys.tips_login_failed.tr);
      return;
    }

    // Once signed in, return the UserCredential
    final result = await FirebaseAuth.instance.signInWithCredential(facebookAuthCredential);
    final uid = result.user?.uid;
    final token = await result.user?.getIdToken();
    final name = result.user?.displayName;
    if (uid != null) {
      loginThird(uid, token!, name);
    } else {
      showToast(LocaleKeys.tips_login_failed.tr);
      return;
    }
  }

  String generateNonce([int length = 32]) {
    final charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._';
    final random = Random.secure();
    return List.generate(length, (_) => charset[random.nextInt(charset.length)]).join();
  }

  /// Returns the sha256 hash of [input] in hex notation.
  String sha256ofString(String input) {
    final bytes = utf8.encode(input);
    final digest = sha256.convert(bytes);
    return digest.toString();
  }

  void signInWithApple() async {
    thirdType = 4;
    final rawNonce = generateNonce();
    final nonce = sha256ofString(rawNonce);

    // Request credential for the currently signed in Apple account.
    final appleCredential = await SignInWithApple.getAppleIDCredential(
      scopes: [
        AppleIDAuthorizationScopes.email,
        AppleIDAuthorizationScopes.fullName,
      ],
      nonce: nonce,
    );

    // Create an `OAuthCredential` from the credential returned by Apple.
    final oauthCredential = OAuthProvider("apple.com").credential(
      idToken: appleCredential.identityToken,
      rawNonce: rawNonce,
    );
    UserCredential user = await FirebaseAuth.instance.signInWithCredential(oauthCredential);
    final uid = user.user?.uid;
    final token = await user.user?.getIdToken();
    final name = user.user?.displayName;
    if (uid != null) {
      EasyLoading.show();
      loginThird(uid, token!, name);
    } else {
      showToast(LocaleKeys.tips_login_failed.tr);
      return;
    }
  }

  void signInWithGoogle() async {
    thirdType = 3;
    final GoogleSignInAccount? googleUser = await GoogleSignIn(
      scopes: [
        'email',
        'https://www.googleapis.com/auth/contacts.readonly',
      ],
    ).signIn();
    final GoogleSignInAuthentication? googleAuth = await googleUser?.authentication;
    if (googleAuth == null) {
      showToast(LocaleKeys.tips_login_failed.tr);
      return;
    }

    EasyLoading.show();
    final AuthCredential credential = GoogleAuthProvider.credential(
      accessToken: googleAuth.accessToken,
      idToken: googleAuth.idToken,
    );
    final authResult = await FirebaseAuth.instance.signInWithCredential(credential);
    final uid = authResult.user?.uid;
    final token = await authResult.user?.getIdToken();
    final name = authResult.user?.displayName;
    if (uid != null) {
      loginThird(uid, token!, name);
    } else {
      EasyLoading.dismiss();
      showToast(LocaleKeys.tips_login_failed.tr);
    }
    logger.v('userCredential ${authResult.user.toString()}');
  }

  void signInWithInstagram() {
    thirdType = 2;
    EasyLoading.show();
    Get.toNamed(Routes.INSWEB, arguments: true, parameters: {
      'title': 'Instagram',
      'url':
          'https://api.instagram.com/oauth/authorize?client_id=426341699191441&redirect_uri=${Server.domain}api/ins/redirect/v1&scope=user_profile,user_media&response_type=code'
    })?.then((value) {
      if (value != null) {
        final params = {
          'client_id': '426341699191441',
          'redirect_uri': '${Server.domain}api/ins/redirect/v1',
          'client_secret': '7c50061b3024ad5152dfe44b837fd3d0',
          'code': value,
          'grant_type': 'authorization_code',
        };
        PublicProvider.oriRequest(
          path: 'https://api.instagram.com/oauth/access_token',
          params: params,
          type: ContentType.formValue,
        ).then(
          (value) {
            final map = value as Map<String, dynamic>;
            final uid = map['user_id'];
            final token = map['access_token'];
            if (uid != null) {
              loginThird(uid.toString(), token, null);
            } else {
              showToast(LocaleKeys.tips_login_failed.tr);
              EasyLoading.dismiss();
              return;
            }
          },
        ).catchError((_) {
          EasyLoading.dismiss();
          showToast(LocaleKeys.tips_login_failed.tr);
        });
      } else {
        EasyLoading.dismiss();
        showToast(LocaleKeys.tips_login_failed.tr);
      }
    }).catchError((_) {
      EasyLoading.dismiss();
    });
  }

  void takeCode() {
    Get.showOverlay(asyncFunction: () => Future.value(), loadingWidget: loadingWidget);
    if (!GetUtils.isEmail(email.value)) {
      showToast(LocaleKeys.tips_email_format.tr);
      return;
    }
    if (time.value != 61) {
      return;
    }
    _timer?.cancel();
    _timer = null;
    _timer = Timer.periodic(Duration(seconds: 1), (timer) {
      if (time.value == 0) {
        _timer?.cancel();
        _timer = null;
        time.value = 61;
        return;
      }
      time.value = time.value - 1;
    });
    provider.takeCode(email.value, 1).then((value) {
      if (!value.isSuccess) {
        _timer?.cancel();
        _timer = null;
        time.value = 61;
      }
      showToast(value.msg ?? '');
    });
  }

  void loginEmail() {
    if (!GetUtils.isEmail(email.value)) {
      showToast(LocaleKeys.tips_email_format.tr);
      return;
    }

    if (loginType.value == LoginType.code && code.value.isEmpty) {
      showToast(LocaleKeys.tips_enter_code.tr);
      return;
    }

    if (loginType.value == LoginType.password && password.value.isEmpty) {
      showToast(LocaleKeys.tips_enter_pass.tr);
      return;
    }
    EasyLoading.show();
    provider
        .loginNormal<UserEntity>(
      email.value,
      code.value,
      password.value,
    )
        .then((value) async {
      if (value.code == 0) {
        String info = json.encode(value.data!.toJson());
        await GlobalConst.sharedPreferences?.setString(Constant.kUser, info);
        AppPages.INITIAL();
      } else {
        showToast(value.msg ?? '');
      }
    }).whenComplete(() {
      EasyLoading.dismiss();
    });
  }

  void loginThird(String thirdId, String thirdToken, String? thirdName) {
    provider.unionLogin(thirdId, thirdType, thirdName, thirdToken).then((value) async {
      if (value.isSuccess) {
        final isRegister = value.data?.isRegister ?? true;
        String info = json.encode(value.data!.toJson());
        if (isRegister) {
          Get.offAndToNamed(Routes.AUTH_REGISTER, arguments: info);
        } else {
          await GlobalConst.sharedPreferences?.setString(Constant.kUser, info);
          await provider.takeMineInfo();
          AppPages.INITIAL();
        }
      } else {
        showToast(value.msg ?? '');
      }
    }).whenComplete(() {
      EasyLoading.dismiss();
    });
  }

  @override
  void onClose() {}
}
